/*
 *  ConcreteNoteGenerator.cpp
 *  SoundController0002
 *
 *  Created by jiro on 11/10/10.
 *  Copyright 2011 jiro music. All rights reserved.
 *
 */

#include "ConcreteNoteGenerator.h"
#include "../../sc/Utility.h"

namespace sc
{
namespace system0039
{

	ConcreteNoteGenerator::ConcreteNoteGenerator( double density, double duration )
		: density( density ),
		  duration( duration )
	{}

	void ConcreteNoteGenerator::AddNote( const ConcreteNote& note )
	{
		notes.push_back( note );
		ReCalcMuteNotes();
	}

	void ConcreteNoteGenerator::AddNotes( const std::vector< ConcreteNote >& notesAdded )
	{
		notes.insert( notes.end(), notesAdded.begin(), notesAdded.end() );
		ReCalcMuteNotes();
	}

	int ConcreteNoteGenerator::GetNoteCount() const
	{
		return duration / GetDurationAverage();
	}

	ConcreteNote ConcreteNoteGenerator::GetConcreteNote() const
	{
		double randomValue = RandomValueGenerator::GetValue( 0.0, 1.0 );
		int index = static_cast< int >( randomValue * notes.size() );
		randomValue = RandomValueGenerator::GetValue( 0.0, 1.0 );
		if ( randomValue < density )
		{
			return notes[ index ];
		}
		return muteNotes[ index ];
	}

	bool ConcreteNoteGenerator::operator == ( const ConcreteNoteGenerator& rhs ) const
	{
		if ( density == rhs.density and
			 duration == rhs.duration and
			 muteNotes == rhs.muteNotes and
			 notes == rhs.notes )
		{
			return true;
		}
		return false;
	}
	
	ConcreteNote ConcreteNoteGenerator::GetMuteConcreteNote() const
	{
		double randomValue = RandomValueGenerator::GetValue( 0.0, 1.0 );
		int index = static_cast< int >( randomValue * notes.size() );
		return muteNotes[ index ];
	}

	double ConcreteNoteGenerator::GetDensity() const
	{
		return density;
	}

	void ConcreteNoteGenerator::ReCalcMuteNotes()
	{
		double durationAverage = GetDurationAverage();
		int muteNoteCount = notes.size();
		muteNotes.clear();
		muteNotes.resize( muteNoteCount );
		double fraction = durationAverage * notes.size();
		for ( int i = 0; i < muteNoteCount; i++ )
		{
			const double dynamics = 0.0;
			const double frequency = 400;
			muteNotes[ i ] = ConcreteNote( 
				frequency, dynamics, 
				frequency + ( ( 1.0 - density ) / density ) * ( notes[ i ].GetDuration() / fraction ), dynamics );
		}
	}
	
	double ConcreteNoteGenerator::GetDurationAverage() const
	{
		double durationAverage = 0.0;
		for ( int i = 0, count = notes.size(); i < count; i++ )
		{
			durationAverage += notes[ i ].GetDuration();
		}
		durationAverage /= notes.size();
		return durationAverage;
	}

}	
}
